`ifndef {{NAME}}_MONITOR__SV
`define {{NAME}}_MONITOR__SV

class {{name}}_monitor extends uvm_monitor;

    virtual {{name}}_if vif;
    uvm_analysis_port #({{name}}_transaction) ap;

    `uvm_component_utils({{name}}_monitor);

    function new(string name = "{{name}}_monitor", uvm_component parent = null);
        super.new(name, parent);
    endfunction

    virtual function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        if (!uvm_config_db#(virtual {{name}}_if)::get(this, "", "vif", vif))
            `uvm_fatal("{{name}}_monitor", "virtual interface must be set for vif!");
        
        ap = new("ap", this);
    endfunction

    extern task main_phase(uvm_phase phase);
    extern task collect_one_pkt({{name}}_transaction tr);
endclass

task {{name}}_monitor::main_phase(uvm_phase phase);
    {{name}}_transaction tr;

    while (1) begin
        tr = new("tr");
        collect_one_pkt(tr);
        ap.write(tr);
    end
endtask

task {{name}}_monitor::collect_one_pkt({{name}}_transaction tr);
    byte unsigned data_q[$];
    byte unsigned data_array[];
    logic [7:0] data;
    logic valid = 0;
    int data_size;

    while (1) begin
        @(posedge vif.clk);
        if (vif.valid) break;
    end

    `uvm_info("{{name}}_monitor", "begin to collect one pkt", UVM_LOW);

    while (vif.valid) begin
        data_q.push_back(vif.data);
        @(posedge vif.clk);
    end

    data_size = data_q.size();
    data_array = new[data_size];

    for (int i = 0; i < data_size; i++) begin
        data_array[i] = data_q[i];
    end

    tr.pload = new[data_size - 18]; // dmac:6, smac:6, ether_type:2, crc:4
    data_size = tr.unpack_bytes(data_array) / 8;

    `uvm_info("{{name}}_monitor", "end collect one pkt, print it:", UVM_LOW);
    tr.print();
endtask

`endif